#include <stdlib.h>
#include "Arbre.h"
#include "Symbole.h"
#include "SymboleValue.h"




////////////////////////////////////////////////////////////////////////////////
// NoeudSeqInst
////////////////////////////////////////////////////////////////////////////////

NoeudSeqInst::NoeudSeqInst() : tabInst() {
}

////////////////////////////////////////////////////////////////////////////////
int NoeudSeqInst::getValeur() {
  int valeur=0;
  for (unsigned int i=0; i<tabInst.size(); i++)
    valeur = tabInst[i]->getValeur();  // on evalue chaque instruction de la séquence
  return valeur; // par convention, resultat = valeur de la derniere instruction
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSeqInst::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Sequence de " << tabInst.size() << " instruction(s)" << endl;
  for (unsigned int i=0; i<tabInst.size(); i++)
    tabInst[i]->afficher(indentation+1); // on affiche les fils en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSeqInst::ajouteInstruction(Noeud* instruction) {
  tabInst.push_back(instruction);
}




////////////////////////////////////////////////////////////////////////////////
// NoeudAffectation
////////////////////////////////////////////////////////////////////////////////

NoeudAffectation::NoeudAffectation(Noeud* variable, Noeud* expression) {
  this->variable=variable;
  this->expression=expression;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudAffectation::getValeur() {
  int valeur = expression->getValeur(); // on évalue l'expression
  ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
  return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////
void NoeudAffectation::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Affectation" << endl;
  variable->afficher(indentation+1);   // on affiche variable et expression
  expression->afficher(indentation+1); // en augmentant l'indentation
}


////////////////////////////////////////////////////////////////////////////////
// NoeudSi
////////////////////////////////////////////////////////////////////////////////

NoeudSi::NoeudSi(Noeud* expbool, Noeud* seqInst, Noeud* siSuivant) {
  this->expBool=expbool;
  this->seqInst=seqInst;
  this->siSuivant=siSuivant;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudSi::getValeur() {
  int valeur = 1; // on évalue l'expression
  if (expBool->getValeur() == 1) seqInst->getValeur();
  if (siSuivant != NULL) siSuivant->getValeur();
//  ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
  return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSi::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Si" << endl;
  expBool->afficher(indentation+1);   // on affiche variable et expression
  seqInst->afficher(indentation+1); // en augmentant l'indentation
  if (siSuivant != NULL)
	  siSuivant->afficher(indentation+1); // en augmentant l'indentation
}


////////////////////////////////////////////////////////////////////////////////
// NoeudPour
////////////////////////////////////////////////////////////////////////////////

NoeudPour::NoeudPour(Noeud* aff, Noeud* affDroite, Noeud* expbool, Noeud* seqInst) {
  this->expBool=expbool;
  this->seqInst=seqInst;
  this->aff=aff;
  this->affDroite=affDroite;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudPour::getValeur() {
  int valeur = 1; // on évalue l'expression
//  ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
  for (aff->getValeur();expBool->getValeur(); affDroite->getValeur())
    seqInst->getValeur(); // on affiche les fils en augmentant l'indentation
  return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////
void NoeudPour::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Pour" << endl;
  aff->afficher(indentation+1);   // on affiche variable et expression
  expBool->afficher(indentation+1);   // on affiche variable et expression
  affDroite->afficher(indentation+1);   // on affiche variable et expression
  seqInst->afficher(indentation+1); // en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
// NoeudTantQue
////////////////////////////////////////////////////////////////////////////////

NoeudTantQue::NoeudTantQue(Noeud* expbool, Noeud* seqInst) {
  this->expBool=expbool;
  this->seqInst=seqInst;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudTantQue::getValeur() {
  int valeur =1; // on évalue l'expression
  while (expBool->getValeur() == 1) { seqInst->getValeur(); }
//  ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
  return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////
void NoeudTantQue::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - TantQue" << endl;
  expBool->afficher(indentation+1);   // on affiche variable et expression
  seqInst->afficher(indentation+1); // en augmentant l'indentation

}


////////////////////////////////////////////////////////////////////////////////
// NoeudRepeter
////////////////////////////////////////////////////////////////////////////////

NoeudRepeter::NoeudRepeter(Noeud* expbool, Noeud* seqInst) {
  this->expBool=expbool;
  this->seqInst=seqInst;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudRepeter::getValeur() {
  int valeur =1; // on évalue l'expression
  do { seqInst->getValeur(); }
  while (expBool->getValeur() == 1);
//  ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
  return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////
void NoeudRepeter::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Repeter" << endl;
  seqInst->afficher(indentation+1); // en augmentant l'indentation
  expBool->afficher(indentation+1);   // on affiche variable et expression
}


////////////////////////////////////////////////////////////////////////////////
// NoeudLire
////////////////////////////////////////////////////////////////////////////////

NoeudLire::NoeudLire(Noeud* variable) {
  this->variable=variable;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudLire::getValeur() {
  int valeur;
//  ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
 // return valeur; // par convention, une affectation a pour valeur la valeur affectée
  variable->afficher();
  cout << "Nouvelle valeur ?" << endl;
  cin >> valeur;
  ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
  return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////
void NoeudLire::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Lire" << endl;
  variable->afficher(indentation+1);   // on affiche variable et expression
//  expression->afficher(indentation+1); // en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
// NoeudEcrire
////////////////////////////////////////////////////////////////////////////////

NoeudEcrire::NoeudEcrire(Noeud* expression) {
  this->expression=expression;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudEcrire::getValeur() {
  int valeur = expression->getValeur(); // on évalue l'expression
  return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////
void NoeudEcrire::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Ecrire" << endl;
  expression->afficher(indentation+1); // on affiche l'expression a ecrire en augmentant l'indentation
}



////////////////////////////////////////////////////////////////////////////////
// NoeudOperateurBinaire
////////////////////////////////////////////////////////////////////////////////

NoeudOperateurBinaire::NoeudOperateurBinaire ( Symbole operateur,
                                               Noeud* operandeGauche,
                                               Noeud* operandeDroit) {
  this->operateur=operateur;
  this->operandeGauche=operandeGauche;
  this->operandeDroit=operandeDroit;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudOperateurBinaire::getValeur() { 
  int valeur=0;
  int og=operandeGauche->getValeur();
  int od=operandeDroit->getValeur();
  if      (this->operateur=="+") valeur = og+od; 
  else if (this->operateur=="-") valeur = og-od;
  else if (this->operateur=="*") valeur = og*od; 
  else if (this->operateur=="/") {
	if (od!=0)
		valeur = og/od;
  	else {
	  	cout << "Erreur pendant l'interpretation : division par zero" << endl;
	  	exit(0); // plus tard on levera une exception
  	}
  }
  else if (this->operateur=="et") {
    if (og==0) valeur = 0;
    else {
      if (od==1) valeur = 1;
    }
  }
  else if (this->operateur=="ou") {
    if (og==1) valeur = 1;
    else {
      if (od==0) valeur = 0;
    }
  }
  else if (this->operateur=="==") {
    if (og == od) valeur = 1;
  }
  else if (this->operateur=="!=") {
    if (og != od) valeur = 1;
  }
  else if (this->operateur=="<") {
    if (og < od) valeur = 1;
  }
  else if (this->operateur=="<=") {
    if (og <= od) valeur = 1;
  }
  else if (this->operateur==">") {
    if (og > od) valeur = 1;
  }
  else if (this->operateur==">=") {
    if (og >= od) valeur = 1;
  }
  else if (this->operateur=="!") {
    if (od == 0) valeur = 1;
  }
  return valeur;
}

////////////////////////////////////////////////////////////////////////////////
void NoeudOperateurBinaire::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Operateur Binaire \"" << this->operateur.getChaine() << "\" applique a : " << endl;
  operandeGauche->afficher(indentation+1);  // on affiche fils gauche et fils droit
  operandeDroit->afficher(indentation+1);   // en augmentant l'indentation
}
